code source game Bi-a 3D

23.675 lượt xem;
1 using System.Collections;
2 using
ThreeDPool.Managers;
3 using
ThreeDPool.EventHandlers;
4 using
UnityEngine;
5
6 namespace
ThreeDPool.Controllers
7 {
8     
class CueController : MonoBehaviour
9     {
10         
[SerializeField]
11         
private Transform _cueBall = null;
12
13         
// distance from the cue ball
14         
private float _defaultDistFromCueBall;
15
16         
private float _maxClampDist = 9;
17
18         
// the distance from cue ball to the cue determines the force gathered
19         
private float _forceGathered = 0.0f;
20
21         
// minimum force threshold required to consider a valid shot
22         
private float _forceThreshold = 0.5f;
23
24         
private float _speed = 10.0f;
25         
private bool _cueReleasedToStrike = false;
26
27         
private Vector3 _initialPos;
28         
private Vector3 _initialDir;
29
30         
// this is the position to rotate around when the ball is been striked to stationary
31         
// the default value for this vector should be one to avoid unexpected behavior
32         
private Vector3 _posToRot = Vector3.one;
33
34         
public float ForceGatheredToHit { get { return _forceGathered; } }
35
36         
private void Start()
37         {
38             
// cache the initial position and rotation
39             _initialPos = transform.position;
40             _initialDir = transform.forward;
41
42             
// making sure the distance is same as what we started with
43             _defaultDistFromCueBall = Vector3.Distance(_cueBall.position, transform.position);
44
45             EventManager.Subscribe(
typeof(GameInputEvent).Name, OnGameInputEvent);
46             EventManager.Subscribe(
typeof(CueBallActionEvent).Name, OnCueBallEvent);
47             EventManager.Subscribe(
typeof(GameStateEvent).Name, OnGameStateEvent);
48         }
49
50         
private void OnDestroy()
51         {
52             EventManager.Unsubscribe(
typeof(GameInputEvent).Name, OnGameInputEvent);
53             EventManager.Unsubscribe(
typeof(CueBallActionEvent).Name, OnCueBallEvent);
54             EventManager.Unsubscribe(
typeof(GameStateEvent).Name, OnGameStateEvent);
55         }
56
57         
private void OnGameInputEvent(object sender, IGameEvent gameEvent)
58         {
59             GameInputEvent gameInputEvent = (GameInputEvent)gameEvent;
60             
// start moving the cue stick towards the ball
61             
switch (gameInputEvent.State)
62             {
63                 
case GameInputEvent.States.HorizontalAxisMovement:
64                     {
65                         
if (_posToRot == Vector3.one)
66                             transform.RotateAround(_cueBall.position, Vector3.up,
20f * gameInputEvent.axisOffset * Time.deltaTime);
67                         
else
68                             transform.RotateAround(_posToRot, Vector3.up,
20f * gameInputEvent.axisOffset * Time.deltaTime);
69                     }
70                     
break;
71                 
case GameInputEvent.States.VerticalAxisMovement:
72                     {
73                         
// this means that the ball is moving
74                         
if (_posToRot != Vector3.one)
75                             
return;
76
77                         
// clamp the cue movement, else it will be frustrating for the player
78                         
var newPosition = transform.position + transform.forward * gameInputEvent.axisOffset;
79
80                         _forceGathered = Vector3.Distance(_cueBall.position, newPosition);
81                         
if ((_forceGathered < _defaultDistFromCueBall + _maxClampDist) &&
82                             _forceGathered > _defaultDistFromCueBall)
83                         {
84                             transform.position = newPosition;
85                             EventManager.Notify(
typeof(CueActionEvent).ToString(), this, new CueActionEvent() { ForceGathered = _forceGathered });
86                         }
87                         
else
88                         {
89                         }
90
91                     }
92                     
break;
93                 
case GameInputEvent.States.Release:
94                     {
95                         
// the cue ball is not stationary as of now
96                         
if (_posToRot != Vector3.one)
97                             
return;
98
99                         
if (_forceGathered > _defaultDistFromCueBall + _forceThreshold)
100                             _cueReleasedToStrike =
true;
101                     }
102                     
break;
103             }
104         }

105
106         ///
<summary>
107         ///
handle cue controller based on the cue ball events
108         ///
</summary>
109         ///
<param name="sender"></param>
110         ///
<param name="gameEvent"></param>
111         
private void OnCueBallEvent(object sender, IGameEvent gameEvent)
112         {
113             CueBallActionEvent cueBallActionEvent = (CueBallActionEvent)gameEvent;
114
115             
// start moving the cue stick towards the ball
116             
switch (cueBallActionEvent.State)
117             {
118                 
case CueBallActionEvent.States.Stationary:
119                 
case CueBallActionEvent.States.Default:
120                     {
121                         
// making sure everything is clean
122                         _forceGathered =
0f;
123
124                         
// on ready for next shot position the cue controller closer to cue ball
125                         transform.position = _cueBall.transform.position - transform.forward * _defaultDistFromCueBall;
126                         transform.LookAt(_cueBall);
127
128                         _posToRot = Vector3.one;
129                     }
130                     
break;
131                 
case CueBallActionEvent.States.Striked:
132                     {
133                         _cueReleasedToStrike =
false;
134
135                         
// make the cue ball go back in the play state
136                         
if (GameManager.Instance.CurrGameState == GameManager.GameState.Play)
137                         {
138                             
// move the cue backward after striking so that cue ball doesnt touch the cue
139                             StartCoroutine(MoveCueAfterStrike(transform.position, _cueBall.transform.position - transform.forward * _defaultDistFromCueBall *
1.5f, 1.0f));
140                         }
141
142                         transform.LookAt(_cueBall);
143
144                         _posToRot = _cueBall.transform.position;
145                     }
146                     
break;
147             }
148         }
149
150         
private void OnGameStateEvent(object sender, IGameEvent gameEvent)
151         {
152             GameStateEvent gameStateEvent = (GameStateEvent)gameEvent;
153             
switch(gameStateEvent.GameState)
154             {
155                 
case GameStateEvent.State.Play:
156                     {
157                         PlaceInInitialPosAndRot();
158                     }
159                     
break;
160             }
161         }

162
163         ///
<summary>
164         ///
this function makes the cue move after striking the cueball
165         ///
</summary>
166         ///
<param name="source"></param>
167         ///
<param name="target"></param>
168         ///
<param name="overTime"></param>
169         ///
<returns></returns>
170         IEnumerator MoveCueAfterStrike(Vector3 source, Vector3 target,
float overTime)
171         {
172             
float startTime = Time.time;
173             
while (Time.time < startTime + overTime)
174             {
175                 transform.position = Vector3.Lerp(source, target, (Time.time - startTime) / overTime);
176                 
yield return null;
177             }
178             transform.position = target;
179         }
180
181         
private void FixedUpdate()
182         {
183             
if(_cueReleasedToStrike)
184             {
185                 
float step = _speed * Time.deltaTime * (_forceGathered/_speed);
186                 transform.position = Vector3.MoveTowards(transform.position, _cueBall.transform.position, step);
187
188                 
// cue ball will now detect if the cue actually hit it and then behave accordingly
189                 
// this event will be notifies by the cue ball
190             }
191         }
192
193         
private void PlaceInInitialPosAndRot()
194         {
195             _forceGathered =
0f;
196             _cueReleasedToStrike =
false;
197             _posToRot = Vector3.one;
198
199             transform.position = _initialPos;
200             transform.forward = _initialDir;
201         }
202     }
203 }


Gõ tìm kiếm nhanh...